
//
// 110320 - AH - Created.
// 110326 - AH - (Special) Fixed getAllNodes().
// 111002 - AH - Missing java doc.
//

package org.soekrat.engine.swnetwork;

import java.util.Arrays;

import org.soekrat.engine.visitor.TokenizedLine;

/**
 * <p>
 *   A spare-wheel cluster consist of a matched node and it's neighbour nodes
 *   which mean is calculated to be equal to or above the mean of matched node.
 *   
 *   The mean is calculated by a
 *   {@link NodeMeanCalculator} object passed to the constructor.
 * </p>
 * @author Laetitia Le Chatton (LLC)
 * @author Arne Halvorsen (AH)
 */
public final class SpareWheelNetworkCluster 
{
  private final SpareWheelNetworkNode m_keywordNode;
  
  private final SpareWheelNetworkNode[] m_nodes;
  
  private final double m_mean;

  /**
   * <p>
   *   Constructor.
   * </p>
   * @param keywordNode Node that has been matched.
   * @param calc        Calculate means.
   */
  SpareWheelNetworkCluster(SpareWheelNetworkNode keywordNode, 
    NodeMeanCalculator calc)
  {
    m_keywordNode=keywordNode;
    
    SpareWheelNetwork network=keywordNode.getNetwork();
    m_mean=calc.calculate(keywordNode.getNetwork(), keywordNode);
    
    m_nodes=network.getNeighboursEqualOrAboveWeight(keywordNode, m_mean);
  }
  
  /**
   * <p>
   *   Gets the mean weight computed for this cluster.
   * </p>
   * @return Mean weight for cluster.
   */
  public double getMeanWeight(){ return m_mean; }
  
  /**
   * <p>
   *   Gets number of nodes in the cluster (including keyword node).
   * </p>
   * @return Count.
   */
  public int size(){ return m_nodes.length+1; }
  
  /**
   * <p>
   *   Gets node in cluster matched by keyword.
   * </p>  
   */
  public SpareWheelNetworkNode getKeywordNode(){ return m_keywordNode; }
  
  /**
   * <p>
   *   Gets all nodes of the cluster.
   * </p>
   * @return Nodes.
   */
  public SpareWheelNetworkNode[] getAllNodes()
  {
    int n=m_nodes.length;
    SpareWheelNetworkNode[] retVal=new SpareWheelNetworkNode[n+1];
    System.arraycopy(m_nodes, 0, retVal, 0, n);
    retVal[n]=m_keywordNode;
    return retVal;
  }
  
  /**
   * <p>
   *   Gets all nodes except the node matched by keyword.
   * </p>
   * @return Nodes.
   */
  public SpareWheelNetworkNode[] getNodes(){ return m_nodes.clone(); }
  
  @Override
  public String toString() 
  {
    StringBuilder sb=new StringBuilder();
    
    sb.append("mean=").append(m_mean).append(", size=").append(size())
      .append(", keyword-node=").append(m_keywordNode.getName())
      .append(", nodes=[");
    
    boolean first=true;
    for (SpareWheelNetworkNode curr : m_nodes)
    {
      if (!first) sb.append(", ");
      first=false;
      sb.append(curr.getName());
    }
    
    return sb.append("]").toString();
  }
  
  private static final NodeMeanCalculator m_calc=
    new NodeGeometricMeanDoubleEdgesCalculator();
  
  /**
   * <p>
   *   Creates
   *   {@link SpareWheelNetworkCluster} from nodes input matches.
   * </p>
   * @param network {@link SpareWheelNetwork} to create cluster off.
   * @param input   Input to match with nodes.
   * @return Created.
   */
  public static SpareWheelNetworkCluster[] createClusters(
    SpareWheelNetwork network, TokenizedLine input)
  {
    if (network==null)
    {
      throw new NullPointerException("network");
    }
    if (input==null)
    {
      throw new NullPointerException("input");
    }
    
    SpareWheelNetworkNode[] nodes=network.getNodes(input);
    
    int n=nodes.length;
    
    SpareWheelNetworkCluster[] retVal=new SpareWheelNetworkCluster[n];
    
    for (int i=0; i<n; i++) 
    {
      retVal[i]=new SpareWheelNetworkCluster(nodes[i], m_calc);  
    }
    
    return retVal;
  }
  
  /**
   * <p>
   *   Retrieve the cluster given input from visitor.
   * </p>
   * @param network {@link SpareWheelNetwork} to retrieve in.
   * @param input   Input from visitor.
   * @param comp    Comparator to use in order to find the "biggest" cluster
   *                to return.
   * @return Found cluster or {@code null} if none found.
   */
  public static SpareWheelNetworkCluster retrieveCluster(
    SpareWheelNetwork network, TokenizedLine input, SpareWheelClusterComparator comp)
  {
    if (network==null)
    {
      throw new NullPointerException("network");
    }
    if (input==null)
    {
      throw new NullPointerException("input");
    }
    if (comp==null)
    {
      new NullPointerException("comp");
    }
    
    SpareWheelNetworkCluster[] clusters=createClusters(network, input);
    int n=clusters.length;
    
    if (n==0) 
    {
      return null;
    }
    else
    {
      Arrays.sort(clusters, comp);
      return clusters[n-1];
    }    
  }
  
}
